package com.sudo.demo.security.util;

import com.demo.common.base.constant.SysSymbolConstant;
import com.sudo.demo.security.config.JwtProperties;
import com.sudo.demo.security.constant.TokenConstant;
import com.sudo.demo.security.exception.AuthException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.Data;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * JWT工具类
 *
 * @author DayDayUp
 * create on 2023-08-10
 **/
public class JwtUtil {

    private static JwtProperties jwtProperties;

    public JwtUtil(JwtProperties jwtProperties) {
        JwtUtil.jwtProperties = jwtProperties;
    }

    //根据用户名生成token
    //传入的是使用SpringSecurity里的UserDetails
    public static String createToken(String username) {
        Map<String, Object> claimsMap = new HashMap<>();
        // 设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，
        // 这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
        claimsMap.put(Claims.ID, UUID.randomUUID().toString());
        // 签发人
        claimsMap.put(Claims.ISSUER, Claims.ISSUER);
        // 签发时间
        claimsMap.put(Claims.ISSUED_AT, new Date());
        // 过期时间
        Date expirationDate = new Date(System.currentTimeMillis() + jwtProperties.getExpiration());
        claimsMap.put(Claims.EXPIRATION, expirationDate);
        // 主体
        claimsMap.put(Claims.SUBJECT, username);
        JwtBuilder jwtBuilder = Jwts.builder()
                .setClaims(claimsMap)
                .signWith(getSecretKey(), SignatureAlgorithm.HS256);
        return jwtBuilder.compact();
    }

    public static Claims parseToken(String token) {
        JwtParser jwtParser = Jwts.parserBuilder()
                .setSigningKey(getSecretKey())
                .build();
        try {
            token = token.replace(TokenConstant.BEARER, SysSymbolConstant.EMPTY);
            Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
            return claimsJws.getBody();
        } catch (ExpiredJwtException e) {
            throw new AuthException("token已过期");
        } catch (UnsupportedJwtException e) {
            throw new AuthException("token验证类型无法对应");
        } catch (MalformedJwtException e) {
            throw new AuthException("token格式有误");
        } catch (SignatureException e) {
            throw new AuthException("token签名错误");
        } catch (IllegalArgumentException e) {
            throw new AuthException("token参数不合法");
        }
    }

    private static SecretKey getSecretKey() {
        byte[] encodeKey = Decoders.BASE64.decode(jwtProperties.getSecret());
        return Keys.hmacShaKeyFor(encodeKey);
    }

    public static void main(String[] args) {
//        System.out.println(createToken("789456"));
        Claims claims = parseToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI3ODk0NTYiLCJpc3MiOiJpc3MiLCJleHAiOjE2OTI3MzM4MTYsImlhdCI6MTY5MTczMzgxNiwianRpIjoiMmQ2ZDYyNTctYzIxZi00NzA5LTk4MDYtOTY2YmMwM2VmOTk0In0.0F7MD0LX7giWmMD3nQcNU3bdpIX_4PCrHiR8GTPNE58");
        System.out.println(claims.getSubject());

    }

    public static JwtToken createJwtToken(String token) {
        JwtToken jwtToken = new JwtToken();
        jwtToken.setKey(TokenConstant.AUTHORIZATION);
        jwtToken.setValue(TokenConstant.BEARER + token);
        return jwtToken;
    }

    @Data
    public static class JwtToken{
        private String key;
        private String value;
    }
}
